Conversation
WalkthroughAdds jq-based JSON filtering: new Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Filter as QueryResultFilter
participant QR as QueryResult
participant Service as jqService
participant Wasm as jqWasm
User->>Filter: Toggle filter type / enter filter
Filter->>QR: onFilterTypeChange(type) / onChange(filter)
QR->>QR: set state (filterType, clear filter, etc.)
alt jq mode
QR->>Service: runJqFilter(data, filter)
Service->>Wasm: jq.raw(data, filter)
Wasm-->>Service: {stdout, exitCode, stderr}
Service-->>QR: stdout (or throw error)
QR->>QR: set jqResult / jqError
QR->>User: render jqResult or show jqError
else jsonpath mode
QR->>QR: formatResponse with JSONPath
QR->>User: render JSONPath-filtered output
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/bruno-app/src/components/ResponsePane/QueryResult/index.js (1)
160-163: jq output may lack pretty-printing for CodeEditor display.When
filterType === 'jq',formattedDatausesjqResultdirectly (line 162). Per the relevant code snippets,jqResultis rawstdoutfrom jq-wasm without the pretty-printing thatformatResponseapplies viafastJsonFormat().This could result in compact, hard-to-read JSON in the editor. Consider parsing and re-formatting the jq output:
♻️ Proposed fix
+import { safeStringifyJSON, safeParseJSON } from 'utils/common'; + // In formattedData useMemo: if (filterType === 'jq' && filter) { - return jqResult ?? formatResponse(data, dataBuffer, selectedFormat, null); + if (jqResult) { + // Pretty-print the jq result + const parsed = safeParseJSON(jqResult); + return parsed !== undefined ? safeStringifyJSON(parsed, true) : jqResult; + } + return formatResponse(data, dataBuffer, selectedFormat, null); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bruno-app/src/components/ResponsePane/QueryResult/index.js` around lines 160 - 163, When filterType === 'jq' the code returns jqResult raw (jqResult) which is unformatted stdout from jq-wasm; instead parse and pretty-print it before returning so the CodeEditor shows formatted JSON. Update the branch that currently returns jqResult ?? formatResponse(...) to: if jqResult is present, attempt to JSON.parse(jqResult) and pass the parsed value through formatResponse (or fastJsonFormat via formatResponse) to produce pretty-printed output, falling back to the original jqResult string if parsing/formatting fails; ensure you reference the existing symbols filterType, jqResult, formatResponse (and fastJsonFormat used inside it) when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/bruno-app/src/components/ResponsePane/QueryResult/index.js`:
- Around line 146-150: The component captures jq errors via setJqError but never
surfaces them in the UI; modify the QueryResult render to display jqError when
present (similar to how the main error prop is rendered) so users know their jq
filter failed. Locate the QueryResult component state variables (jqError,
jqResult) and the catch block that calls setJqError, then add a conditional
branch in the render output that shows jqError (with appropriate
styling/placement used for error) instead of falling back to the unfiltered data
when jqError is non-empty.
---
Nitpick comments:
In `@packages/bruno-app/src/components/ResponsePane/QueryResult/index.js`:
- Around line 160-163: When filterType === 'jq' the code returns jqResult raw
(jqResult) which is unformatted stdout from jq-wasm; instead parse and
pretty-print it before returning so the CodeEditor shows formatted JSON. Update
the branch that currently returns jqResult ?? formatResponse(...) to: if
jqResult is present, attempt to JSON.parse(jqResult) and pass the parsed value
through formatResponse (or fastJsonFormat via formatResponse) to produce
pretty-printed output, falling back to the original jqResult string if
parsing/formatting fails; ensure you reference the existing symbols filterType,
jqResult, formatResponse (and fastJsonFormat used inside it) when making the
change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0af40d12-a122-49b6-b3bc-57b7b2f763bd
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
packages/bruno-app/package.jsonpackages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.jspackages/bruno-app/src/components/ResponsePane/QueryResult/StyledWrapper.jspackages/bruno-app/src/components/ResponsePane/QueryResult/index.jspackages/bruno-app/src/utils/common/jq-service.jspackages/bruno-electron/src/index.js
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/bruno-app/src/components/ResponsePane/QueryResult/index.js (1)
162-165: Brief flicker during jq filter computation.When
jqResultis null (lines 139-140 clear it), the fallback shows unfiltered data momentarily. This is acceptable UX, but if users find it jarring, consider preserving the previous result until the new one arrives or showing a subtle loading indicator.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bruno-app/src/components/ResponsePane/QueryResult/index.js` around lines 162 - 165, The fallback returns unfiltered data when jqResult is null causing a flicker; change the logic so the UI preserves the previous rendered result (e.g., keep a cached "lastJqResult") or shows a subtle loading state instead of immediately calling formatResponse(data,...). Update the branch that checks filterType === 'jq' && filter to return lastJqResult if jqResult is null (or a loading flag) and only replace lastJqResult when jqResult becomes non-null; use the existing symbols jqResult, filterType, filter, formatResponse, data, dataBuffer, and selectedFormat to find and update the code paths that clear and render jq results.packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.js (1)
61-76: Consider adding accessible labels to toggle buttons.The toggle buttons lack
aria-labeloraria-pressedattributes for screen reader users. This is a minor accessibility enhancement.♿ Suggested accessibility improvement
<button - className={`toggle-btn ${filterType === 'jsonpath' ? 'active' : ''}`} + className={`toggle-btn ${filterType === 'jsonpath' ? 'active' : ''}`} + aria-pressed={filterType === 'jsonpath'} + aria-label="Filter with JSONPath" onClick={() => handleFilterTypeChange('jsonpath')} > JSONPath </button> <button - className={`toggle-btn ${filterType === 'jq' ? 'active' : ''}`} + className={`toggle-btn ${filterType === 'jq' ? 'active' : ''}`} + aria-pressed={filterType === 'jq'} + aria-label="Filter with jq" onClick={() => handleFilterTypeChange('jq')} > jq </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.js` around lines 61 - 76, The toggle buttons for switching filter types lack accessible labeling—update the two buttons in QueryResultFilter so each includes an aria-label (e.g., "Select JSONPath filter" and "Select jq filter") and an aria-pressed attribute tied to the current filterType state (use aria-pressed={filterType === 'jsonpath'} for the JSONPath button and aria-pressed={filterType === 'jq'} for the jq button); keep the existing onClick handlers (handleFilterTypeChange) and class logic intact so the visual and programmatic state remain consistent with isExpanded and mode checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/bruno-app/src/components/ResponsePane/QueryResult/index.js`:
- Line 141: The call to runJqFilter is passing data (which may be a parsed
object) into jq.raw(), causing "[object Object]" errors; update the call site
using runJqFilter(data, filter) to pass a proper JSON string when data is an
object (e.g., JSON.stringify(data)) or pass the original dataBuffer instead so
jq.raw() always receives a raw JSON string; locate usages of runJqFilter and
jq.raw() and ensure either JSON.stringify(data) is used or dataBuffer is
forwarded.
---
Nitpick comments:
In `@packages/bruno-app/src/components/ResponsePane/QueryResult/index.js`:
- Around line 162-165: The fallback returns unfiltered data when jqResult is
null causing a flicker; change the logic so the UI preserves the previous
rendered result (e.g., keep a cached "lastJqResult") or shows a subtle loading
state instead of immediately calling formatResponse(data,...). Update the branch
that checks filterType === 'jq' && filter to return lastJqResult if jqResult is
null (or a loading flag) and only replace lastJqResult when jqResult becomes
non-null; use the existing symbols jqResult, filterType, filter, formatResponse,
data, dataBuffer, and selectedFormat to find and update the code paths that
clear and render jq results.
In
`@packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.js`:
- Around line 61-76: The toggle buttons for switching filter types lack
accessible labeling—update the two buttons in QueryResultFilter so each includes
an aria-label (e.g., "Select JSONPath filter" and "Select jq filter") and an
aria-pressed attribute tied to the current filterType state (use
aria-pressed={filterType === 'jsonpath'} for the JSONPath button and
aria-pressed={filterType === 'jq'} for the jq button); keep the existing onClick
handlers (handleFilterTypeChange) and class logic intact so the visual and
programmatic state remain consistent with isExpanded and mode checks.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 006172e0-9a8f-48eb-b913-c3d6004ede45
📒 Files selected for processing (4)
packages/bruno-app/package.jsonpackages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.jspackages/bruno-app/src/components/ResponsePane/QueryResult/StyledWrapper.jspackages/bruno-app/src/components/ResponsePane/QueryResult/index.js
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/bruno-app/src/components/ResponsePane/QueryResult/StyledWrapper.js
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.js (1)
63-74: Consider addingtype="button"to prevent unintended form submissions.While these buttons aren't inside a form currently, explicitly setting
type="button"is a defensive practice that prevents accidental form submission if the component is ever nested inside a form element.💡 Proposed fix
<button + type="button" className={`toggle-btn ${filterType === 'jsonpath' ? 'active' : ''}`} onClick={() => handleFilterTypeChange('jsonpath')} > JSONPath </button> <button + type="button" className={`toggle-btn ${filterType === 'jq' ? 'active' : ''}`} onClick={() => handleFilterTypeChange('jq')} > jq </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.js` around lines 63 - 74, The toggle buttons for selecting filter type (the JSX buttons that use filterType and onClick={() => handleFilterTypeChange(...)}) should explicitly include type="button" to prevent accidental form submission if this component is later nested inside a form; update both the JSONPath and jq <button> elements to add type="button" while leaving their className and onClick handlers unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.js`:
- Around line 63-74: The toggle buttons for selecting filter type (the JSX
buttons that use filterType and onClick={() => handleFilterTypeChange(...)})
should explicitly include type="button" to prevent accidental form submission if
this component is later nested inside a form; update both the JSONPath and jq
<button> elements to add type="button" while leaving their className and onClick
handlers unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9dab5fe3-c81b-4fe5-957b-3b0e1e6e9b5c
📒 Files selected for processing (1)
packages/bruno-app/src/components/ResponsePane/QueryResult/QueryResultFilter/index.js
jq in response filter
Description
Closes #7423
This PR introduces the ability to filter JSON response either using
jqor JSONPath (JSONPath being the existing behavior). jq offers much more powerful capabilities to manipulate JSON and is a great tool to quickly analyze json responses.The feature presents a selector next to the filter, and the field adapts to the choice. The jq filtering behaves the same as the JSONPath (dynamic while typing, same field).
JSONPath stays the default selection.
To my knowledge, no serious competitor has this feature (except RapidAPI/Paw, and it is MacOS-only). In open-source, there is a long standing issue for Insomnia to get this but it is not going anywhere so far.
I think this feature would represent a real competitive advantage, on top of being a really nice-to-have (I implemented it because I have longed for it in all the tools I have used so far).
Without filter
Proper error handling
This feature leverages
jq-wasm, which is a webassembly build of jq that requires no extra native dependency, and is the library used by the official jq playground.About
wasm-unsafe-evalTo be able to use this webassembly library, the Content Security Policy has to be adjusted, with the
wasm-unsafe-evaldirective enabled.Despite its name, this policy is narrowly scoped, and is actually covered by tests in the Electron project itself. It is also less permissive than several policies already in place in the project.
This policy only affects WebAssembly compilation.
About the added dependency
The gzip size of the bundle increases by ~650kB, which is around 10% of the bundle, but marginal considering the Electron footprint.
Contribution Checklist:
Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.
Summary by CodeRabbit
New Features
Bug Fixes
Style
Chores